package com.dave.gd.core.base.repository.impl;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.support.rowset.SqlRowSet;

import com.dave.gd.common.exception.RtManagerException;
import com.dave.gd.common.log.ILogger;
import com.dave.gd.common.log.LoggerFactory;
import com.dave.gd.common.util.ClassInfoUtils;
import com.dave.gd.common.util.EntityInsFactory;
import com.dave.gd.core.base.dao.impl.BaseDaoImpl;
import com.dave.gd.core.base.entity.impl.AbstractBaseEntity;
import com.dave.gd.core.base.repository.IBaseRepository;
import com.dave.gd.core.common.MybatisTemplate;
import com.dave.gd.core.common.pagehelper.PageInfo;

@SuppressWarnings("rawtypes")
public abstract class AbstractBaseRepository<T extends AbstractBaseEntity, ID extends Serializable>
    extends BaseDaoImpl implements IBaseRepository<T, ID> {
    
    protected ILogger logger = LoggerFactory.getLogger(this.getClass());
    private Class<T>  repositoryClass;
    
    public AbstractBaseRepository(Class<T> repositoryClass) {
        this.repositoryClass = repositoryClass;
    }
    
    public void setRepositoryClass(Class<T> clazz) {
        this.repositoryClass = clazz;
    }
    
    @Override
    public Class<T> getRepositoryClass() {
        return this.repositoryClass;
    }
    
    @Autowired
    private MybatisTemplate mybatisTemplate;
    
    public MybatisTemplate getMybatisTemplate() {
        return mybatisTemplate;
    }
    
    @Override
    public int insert(T t) {
        int i = mybatisTemplate.insert(t);
        return i;
    }
    
    @Override
    public int delete(T t) {
        int i = mybatisTemplate.delete(t);
//        //清除缓存
//        CacheContext.removeEnttFromCache(t.getClass().getName(), t.getId(), t);
        return i;
    }
    
    @Override
    public int update(T t) {
        int i = mybatisTemplate.update(t);
//        //清除缓存
//        CacheContext.removeEnttFromCache(t.getClass().getName(), t.getId(), t);
        return i;
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public T getById(ID id) {
        Map<String, Object> map = new HashMap<String, Object>();
        AbstractBaseEntity<ID> pojo = (AbstractBaseEntity<ID>) EntityInsFactory
            .getInstance(repositoryClass);
        //        map.put(pojo.id(), id);
        map.put(ClassInfoUtils.getIdField(repositoryClass), id);
        
//        //先从缓存获取
//        T entt = (T) CacheContext.getEnttFromCache(repositoryClass.getName(), id);
//        if (entt != null) {
//            return entt;
//        }
        T t = (T) mybatisTemplate.getObjectByMap(repositoryClass, map);
//        //放入缓存
//        if (t != null) {
//            CacheContext.setEnttToCache(t.getClass().getName(), id, t);
//        }
        return t;
    }
    
    /**
     * 根据框架生成查询语句，尽量少用
     */
    @Deprecated
    @Override
    public List<T> queryAll() {
        Map<String, Object> map = new HashMap<String, Object>();
        List<T> list = (List<T>) mybatisTemplate.getObjectListByMap(repositoryClass, map);
//        if (list != null && list.size() > 0) {
//            for (T t : list) {
//                CacheContext.setEnttToCache(t.getClass().getName(), t.getId(), t);
//            }
//        }
        return list;
    }
    
    /**
     * 根据框架生成查询语句，尽量少用
     */
    @Deprecated
    @Override
    public List<T> queryByMap(Map<String, Object> map) {
        List<T> list = (List<T>) mybatisTemplate.getObjectListByMap(repositoryClass, map);
//        if (list != null && list.size() > 0) {
//            for (T t : list) {
//                CacheContext.setEnttToCache(t.getClass().getName(), t.getId(), t);
//            }
//        }
        return list;
    }
    
    /**
     * 根据框架生成查询语句，尽量少用
     */
    @Deprecated
    public PageInfo<T> queryPageInfoByMap(Map<String, Object> map, int page, int pageSize) {
        PageInfo<T> info = mybatisTemplate.getPageInfoByMap(repositoryClass, map, page, pageSize);
        List<T> list = info.getList();
//        if (list != null && list.size() > 0) {
//            for (Object t : list) {
//                if (t instanceof AbstractBaseEntity) {
//                    AbstractBaseEntity entt = (AbstractBaseEntity) t;
//                    CacheContext.setEnttToCache(entt.getClass().getName(), entt.getId(), entt);
//                }
//            }
//        }
        return info;
    }
    
    private Map<String, String> sqlMap = new HashMap<String, String>();
    
    /**
     * 向仓库注册SQL语句。
     * 
     * @param sqlName
     *            SQL语句名称
     * @param sql
     *            SQL语句
     */
    protected void registerSql(String sqlName, String sql) {
        this.sqlMap.put(sqlName, sql);
    }
    
    @Override
    public int jdbcQueryForIntByName(String name, Object... args) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForInt(sql, args);
    }
    
    @Override
    public int jdbcQueryForIntByName(String name, Object[] args, int[] argTypes) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForInt(sql, args, argTypes);
    }
    
    @Override
    public int jdbcQueryForIntByName(String name) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForInt(sql);
    }
    
    @Override
    public <E> List<E> jdbcQueryForListByName(String name, Class<E> elementType, Object... args) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForList(sql, elementType, args);
    }
    
    @Override
    public <E> List<E> jdbcQueryForListByName(String name, Class<E> elementType) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForList(sql, elementType);
    }
    
    @Override
    public List<Map<String, Object>> jdbcQueryForListByName(String name, Object... args) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForList(sql, args);
    }
    
    @Override
    public <E> List<E> jdbcQueryForListByName(String name, Object[] args, Class<E> elementType) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForList(sql, args, elementType);
    }
    
    @Override
    public <E> List<E> jdbcQueryForListByName(String name, Object[] args, int[] argTypes,
        Class<E> elementType) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForList(sql, args, argTypes, elementType);
    }
    
    @Override
    public List<Map<String, Object>> jdbcQueryForListByName(String name, Object[] args,
        int[] argTypes) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForList(sql, args, argTypes);
    }
    
    @Override
    public List<Map<String, Object>> jdbcQueryForListByName(String name) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForList(sql);
    }
    
    @Override
    public <E> List<E> jdbcFindListByName(String name, Class<E> elementType) {
        String sql = this.getSqlByName(name);
        return this.jdbcFindList(sql, elementType);
    }
    
    @Override
    public <E> List<E> jdbcFindListByName(String name, Class<E> elementType, List<Object> params) {
        String sql = this.getSqlByName(name);
        return this.jdbcFindList(sql, elementType, params);
    }
    
    @Override
    public int jdbcGetSizeByName(String name, List<Object> params) {
        String sql = this.getSqlByName(name);
        return this.jdbcGetSize(sql, params);
    }
    
    @Override
    public <E> PageInfo<E> jdbcFindPageInfoByName(String name, Class<E> elementType, int currentPage,
        int perPageNum) {
        String sql = this.getSqlByName(name);
        return this.jdbcFindPageInfo(sql, elementType, currentPage, perPageNum);
    }
    
    @Override
    public <E> PageInfo<E> jdbcFindPageInfoByName(String name, Class<E> elementType,
        List<Object> params, int currentPage, int perPageNum) {
        String sql = this.getSqlByName(name);
        return this.jdbcFindPageInfo(sql, elementType, params, currentPage, perPageNum);
    }
    
    @Override
    public long jdbcQueryForLongByName(String name, Object... args) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForLong(sql, args);
    }
    
    @Override
    public long jdbcQueryForLongByName(String name, Object[] args, int[] argTypes) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForLong(sql, args, argTypes);
    }
    
    @Override
    public long jdbcQueryForLongByName(String name) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForLong(sql);
    }
    
    @Override
    public Map<String, Object> jdbcQueryForMapByName(String name, Object... args) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForMap(sql, args);
    }
    
    @Override
    public Map<String, Object> jdbcQueryForMapByName(String name, Object[] args, int[] argTypes) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForMap(sql, args, argTypes);
    }
    
    @Override
    public Map<String, Object> jdbcQueryForMapByName(String name) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForMap(sql);
    }
    
    @Override
    public <E> E jdbcQueryForObjectByName(String name, Class<E> requiredType, Object... args) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForObject(sql, requiredType, args);
    }
    
    @Override
    public <E> E jdbcQueryForObjectByName(String name, Class<E> requiredType) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForObject(sql, requiredType);
    }
    
    @Override
    public <E> E jdbcQueryForObjectByName(String name, Object[] args, Class<E> requiredType) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForObject(sql, args, requiredType);
    }
    
    @Override
    public <E> E jdbcQueryForObjectByName(String name, Object[] args, int[] argTypes,
        Class<E> requiredType) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForObject(sql, args, argTypes, requiredType);
    }
    
    @Override
    public SqlRowSet jdbcQueryForRowSetByName(String name, Object... args) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForRowSet(sql, args);
    }
    
    @Override
    public SqlRowSet jdbcQueryForRowSetByName(String name, Object[] args, int[] argTypes) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForRowSet(sql, args, argTypes);
    }
    
    @Override
    public SqlRowSet jdbcQueryForRowSetByName(String name) {
        String sql = this.getSqlByName(name);
        return this.jdbcQueryForRowSet(sql);
    }
    
    /**
     * 根据SQL名称，获取对应的SQL语句。
     * 
     * @param sqlName
     *            SQL语句名称
     * @return SQL语句
     */
    protected String getSqlByName(String sqlName) {
        String hql = this.sqlMap.get(sqlName);
        if (hql == null) {
            throw new RtManagerException("无法根据名称：@sqlName，查找sql定义", this.getClass(),
                "getSqlByName", "sqlNull", "@sqlName", sqlName);
        }
        return hql;
    }
    
    
}
